-module(parser).

-export([
    debug/1,
    parse/1,
    tokenize/4
]).

parse(SendTo) ->
    parse([],SendTo,wait).

parse(Accum,SendTo,TokenState) ->
    receive
        {ok,[]} ->
            %call parse without clearing accum and keep waiting for a real line
            parse(Accum,SendTo,TokenState);
        {ok,Line} ->
            %tokenize, send to receiving thread, and get state and accum
            {NewAccum, NewToken} = tokenize(Line,[],TokenState,SendTo),
            %continue parsing using leftovers as accum
            parse(NewAccum,SendTo,NewToken);
        done ->
            SendTo ! done;
        _ ->
            %need to modify to throw exception
            parse(Accum,SendTo,TokenState)
    end.

%state atoms
% header - used for head
% question - used to denote question
% string - string literal
% option - options
% answer - answer
% wait - hit ; and waiting for next token
tokenize([], Accum, TokenState, _) -> {Accum, TokenState};
tokenize(Stream, Accum, TokenState, SendTo) ->
    %grab character and list
    [Character|List] = Stream,
    %do a task based on tokenizing state to send proper tokens to interpreter
    %the value 34 is equal to " in the ascii system used by erlang
    %the value 32 is equal to SPACE in the ascii system used by erlang
    %the value 72 is equal to H in ascii, used for the header token
    %the value 78 is equal to O in ascii, used for the option token
    %the value 65 is equal to A in ascii, used for the answer token
    %the value 81 is equal to Q in ascii, used for the question token
   if
        TokenState == wait ->
            case Character of
                72 -> SendTo ! header, tokenize(List,[],header,SendTo);
                34 -> tokenize(List,[],string,SendTo);
                79 -> SendTo ! option, tokenize(List,[],option,SendTo);
                65 -> SendTo ! answer, tokenize(List,[],answer,SendTo);
                81 -> SendTo ! question, tokenize(List,[],question,SendTo);
                _ -> tokenize(List,[],wait,SendTo)
            end;
        TokenState == header orelse TokenState == question orelse TokenState == answer orelse TokenState == option ->
            case Character of
                %on space, ignore
                32 -> tokenize(List,[],header,SendTo);
                %on " send as string, and parse string
                34 -> tokenize(List,[],string,SendTo)
            end;
        TokenState == string ->
            case Character of
                % on ", stop parsing and go back to looking for tokens
                34 -> SendTo ! Accum, tokenize(List,[],wait,SendTo);
                % on any other value, continue adding to string
                _ -> tokenize(List,Accum ++ [Character],string,SendTo)
            end
    end.

debug(File) ->
    {ok, Device} = file:open(File,[write]),
    debug_print(Device).

debug_print(Device) ->
    receive
        Value ->
            io:fwrite(Device,"~s~n",[Value]),
            debug_print(Device)
    end.